package lelouet.datacenter.simulation.eventhandlers;

import java.util.Collections;
import java.util.List;

import lelouet.datacenter.simulation.DataCenter;
import lelouet.datacenter.simulation.Event;
import lelouet.datacenter.simulation.EventHandler;
import lelouet.datacenter.simulation.Hypervisor;
import lelouet.datacenter.simulation.VM;
import lelouet.datacenter.simulation.Event.EventStates;
import lelouet.datacenter.simulation.events.VMStateChanged;
import lelouet.datacenter.simulation.events.VMStateChanged.VMStates;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link EventHandler} that only handles state changes from EXTERNAL to
 * UNALLOCATED and set them to solved, and allocates the VM to a
 */
public class BasicAllocatorHandler extends DiscardEventHandler {

	private final static Logger mlogger = LoggerFactory
			.getLogger(BasicAllocatorHandler.class);

	private final DataCenter target;

	public BasicAllocatorHandler(DataCenter dc) {
		mlogger.debug("creation, linked to {}", dc.getId());
		target = dc;
	}

	@Override
	public List<Event> handleStateChanged(VMStateChanged event) {
		if (event.before == VMStates.EXTERNAL
				&& event.after == VMStates.UNALLOCATED
				&& event.getState() != EventStates.RESOLVED) {
			VM vm = event.vm;
			mlogger.debug("allocating vm {} in datacenter {}", vm.getId(),
					target.getId());
			for (Hypervisor hp : target.getHypervisors().values()) {
				long usedmem = hp.getVMsAllocatedMem();
				long freemem = hp.getVMsDedicatedMem() - usedmem;
				if (vm.getMemUsed() <= freemem) {
					mlogger.debug("starting vm {} on hypervisor {}",
							vm.getId(), hp.getId());
					hp.startVM(vm);
					event.setState(EventStates.RESOLVED);
					return Collections.emptyList();
				} else {
					mlogger
							.debug(
									"hypervisor {} has {} Mo ram free({} dedicated, {} used) but vm {} requires {}",
									new Object[] { hp.getId(), freemem,
											hp.getVMsDedicatedMem(), usedmem,
											vm.getId(), vm.getMemUsed() });
				}
			}
		}
		return Collections.emptyList();
	}
}
